//package cn.jingyuan.owl.web.mapping;
//
//import cn.jingyuan.owl.utils.core.ReflectUtils;
//import cn.jingyuan.owl.utils.core.StringUtils;
//import io.swagger.annotations.ApiOperation;
//import org.springframework.boot.context.event.ApplicationReadyEvent;
//import org.springframework.context.ApplicationListener;
//import org.springframework.context.ConfigurableApplicationContext;
//import org.springframework.core.MethodParameter;
//import org.springframework.core.env.Environment;
//import org.springframework.http.MediaType;
//import org.springframework.security.access.ConfigAttribute;
//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
//import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
//import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
//import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
//import org.springframework.security.web.util.matcher.RequestMatcher;
//import org.springframework.util.AntPathMatcher;
//import org.springframework.util.DigestUtils;
//import org.springframework.web.bind.annotation.RequestBody;
//import org.springframework.web.bind.annotation.RequestMethod;
//import org.springframework.web.bind.annotation.RestController;
//import org.springframework.web.method.HandlerMethod;
//import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
//import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
//import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
//import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
//
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.Iterator;
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//
///**
// * SpringBoot ApiProcessor 实现
// */
//public class SpringBootApiProcessor extends AbstractApiProcessor implements ApplicationListener<ApplicationReadyEvent> {
//
//    /**
//     * 忽略的资源
//     */
//    protected final List<String> IGNORE_URLS = new ArrayList<>();
//
//    private final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
//
//    public SpringBootApiProcessor() {
//        super();
//        IGNORE_URLS.add("/error");
//    }
//
//    @Override
//    public Collection<String> getIgnoreUrls() {
//        return IGNORE_URLS;
//    }
//
//    @Override
//    public void addIgnoreUrls(Collection<String> urls) {
//        if (urls != null && !urls.isEmpty()) {
//            // FIXME 校验 urls 的有效性
//            IGNORE_URLS.addAll(urls);
//        }
//    }
//
//    /**
//     * 初始化方法
//     */
//    @Override
//    public void onApplicationEvent(ApplicationReadyEvent event) {
//        if (!enableScan) {
//            return;
//        }
//
//        ConfigurableApplicationContext context = event.getApplicationContext();
//        Environment environment = context.getEnvironment();
//
//        ApiPostProcessService scanPostProcessService = context.getBean(ApiPostProcessService.class);
//        if (null == scanPostProcessService) {
//            throw new RuntimeException("未发现" + ApiPostProcessService.class.getSimpleName() + " 服务");
//        }
//
//        // 服务名称
//        if (null == application) {
//            application = environment.getProperty("spring.application.name");
//        }
//
//        if (null == application) {
//            throw new IllegalArgumentException("serviceId cannot be empty");
//        }
//
//        // FIXME contextPath
//        contextPath = environment.getProperty("xxx");
//
//        // 所有接口映射
//        RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
//
//        // 获取 url 与类和方法的对应信息
//        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
//
//        List<RequestMatcher> permitAll = new ArrayList<>();
//
//        // FIXME 考虑柔性实现，不强制依赖 spring-security-xxx 模块
//        try {
//            // 获取所有安全配置适配器
//            Map<String, WebSecurityConfigurerAdapter> securityConfigMap = context.getBeansOfType(WebSecurityConfigurerAdapter.class);
//            Iterator<Map.Entry<String, WebSecurityConfigurerAdapter>> iterable = securityConfigMap.entrySet().iterator();
//
//            while (iterable.hasNext()) {
//                WebSecurityConfigurerAdapter configurer = iterable.next().getValue();
//                HttpSecurity httpSecurity = (HttpSecurity) ReflectUtils.getFieldValue(configurer, "http");
//                FilterSecurityInterceptor filterSecurityInterceptor = httpSecurity.getSharedObject(FilterSecurityInterceptor.class);
//                FilterInvocationSecurityMetadataSource metadataSource = filterSecurityInterceptor.getSecurityMetadataSource();
//                Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = (Map) ReflectUtils.getFieldValue(metadataSource, "requestMap");
//
//                Iterator<Map.Entry<RequestMatcher, Collection<ConfigAttribute>>> requestIterable = requestMap.entrySet().iterator();
//                while (requestIterable.hasNext()) {
//                    Map.Entry<RequestMatcher, Collection<ConfigAttribute>> match = requestIterable.next();
//                    if (match.getValue().toString().contains("permitAll")) {
//                        permitAll.add(match.getKey());
//                    }
//                }
//            }
//        } catch (Exception e) {
//            throw e;
//        }
//
//        List<ApiMetadata> apiMetadata = new ArrayList<>();
//        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
//            RequestMappingInfo mappingInfo = entry.getKey();
//            HandlerMethod handlerMethod = entry.getValue();
//
//            boolean ignore = MatchIgnoreApiUtils.isIgnore(handlerMethod);
//            if (ignore) {
//                continue;
//            }
//
//            // 请求路径
//            PatternsRequestCondition patternsCondition = mappingInfo.getPatternsCondition();
//            String urls = getUrls(patternsCondition.getPatterns());
//
//            // 忽略指定的 urls
//            // FIXME 需要优化判断逻辑，防止多个请求映射为在一个 method 上
//            if (IGNORE_URLS.contains(urls)) {
//                continue;
//            }
//
//            // FIXME 优先获取  RequestMapping produces 的属性
//             /*
//                判断 MediaType 是否为 Json
//                    a)：Controller 是否被 RestController.class 修饰
//                    b)：请求参数中包含 RequestBody.class
//                    c)：方法是否被 ResponseBody.class 修饰
//            */
//            Set<MediaType> mediaTypeSet = mappingInfo.getProducesCondition().getProducibleMediaTypes();
//            if (null != handlerMethod.getMethod().getDeclaringClass().getAnnotation(RestController.class)) {
//                mediaTypeSet.add(MediaType.APPLICATION_JSON);
//            } else if (null != handlerMethod.getMethod().getAnnotation(RequestBody.class)) {
//                mediaTypeSet.add(MediaType.APPLICATION_JSON);
//            } else {
//                for (MethodParameter params : handlerMethod.getMethodParameters()) {
//                    if (params.hasParameterAnnotation(RequestBody.class)) {
//                        mediaTypeSet.add(MediaType.APPLICATION_JSON);
//                        break;
//                    }
//                }
//            }
//
//            String mediaTypes = getMediaTypes(mediaTypeSet);
//
//            // 请求类型
//            RequestMethodsRequestCondition methodsCondition = mappingInfo.getMethodsCondition();
//            String methods = getMethods(methodsCondition.getMethods());
//
//            // 方法名 类名
//            String className = handlerMethod.getMethod().getDeclaringClass().getName();
//            String methodName = handlerMethod.getMethod().getName();
//
//            // md5 码
//            String md5 = DigestUtils.md5DigestAsHex((application + urls).getBytes());
//
//            String name = "";
//            String desc = "";
//
//            // 是否需要安全认证 默认：1-是 0-否
//            String isAuth = "1";
//
//            // 匹配项目中 .permitAll() 配置
//            for (String url : patternsCondition.getPatterns()) {
//                for (RequestMatcher requestMatcher : permitAll) {
//                    if (requestMatcher instanceof AntPathRequestMatcher) {
//                        AntPathRequestMatcher pathRequestMatcher = (AntPathRequestMatcher) requestMatcher;
//                        if (PATH_MATCHER.match(pathRequestMatcher.getPattern(), url)) {
//                            // 忽略验证
//                            isAuth = "0";
//                        }
//                    }
//                }
//            }
//
//            ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
//            if (null != apiOperation) {
//                name = apiOperation.value();
//                desc = apiOperation.notes();
//            }
//
//            name = StringUtils.isBlank(name) ? methodName : name;
//
//            ApiMetadata apiMetadata = new ApiMetadata()
//                    .setApplication(application)
//                    .setContextPath(contextPath)
//                    .setCode(md5)
//                    .setPath(urls)
//                    .setPathInfo(name)
//                    .setDescription(desc)
//                    .setHttpMethods(methods)
//                    .setContentTypes(mediaTypes)
//                    .setClassName(className)
//                    .setClassMethodName(methodName)
//                    .setMd5(md5)
//                    .setIsAuth(isAuth);
//
//            apiMetadata.add(apiMetadata);
//        }
//
//        log.info("ApplicationReadyEvent:{}", application);
//
//        scanPostProcessService.scanPostProcess(apiMetadata);
//    }
//
//    private String getMediaTypes(Set<MediaType> mediaTypes) {
//        StringBuilder builder = new StringBuilder();
//        for (MediaType mediaType : mediaTypes) {
//            builder.append(mediaType.toString()).append(",");
//        }
//
//        if (mediaTypes.size() > 0) {
//            builder.deleteCharAt(builder.length() - 1);
//        }
//
//        return builder.toString();
//    }
//
//    private String getMethods(Set<RequestMethod> requestMethods) {
//        StringBuilder builder = new StringBuilder();
//        for (RequestMethod requestMethod : requestMethods) {
//            builder.append(requestMethod.toString()).append(",");
//        }
//
//        if (requestMethods.size() > 0) {
//            builder.deleteCharAt(builder.length() - 1);
//        }
//
//        return builder.toString();
//    }
//
//    private String getUrls(Set<String> urls) {
//        StringBuilder builder = new StringBuilder();
//        for (String url : urls) {
//            builder.append(url).append(",");
//        }
//
//        if (urls.size() > 0) {
//            builder.deleteCharAt(builder.length() - 1);
//        }
//
//        return builder.toString();
//    }
//
//}
